#include "KeyboardController.h"
#include "core/utils/LimelightUtils.h"
#include "core/utils/XComponentUtils.h"
#include <ace/xcomponent/native_xcomponent_key_event.h>
#include <Limelight.h>

#undef LOG_DOMAIN
#undef LOG_TAG
#define LOG_DOMAIN  0x0
#define LOG_TAG     "KeyboardController"
#include <hilog/log.h>


namespace {
constexpr bool DEBUG = false;
}

KeyboardController::KeyboardController() {
}

KeyboardController::~KeyboardController() {
}


namespace {
const std::unordered_map<OH_NativeXComponent_KeyAction, char> actionMap = {
    {OH_NATIVEXCOMPONENT_KEY_ACTION_DOWN, KEY_ACTION_DOWN},
    {OH_NATIVEXCOMPONENT_KEY_ACTION_UP, KEY_ACTION_UP},
};

struct LiKeyCode {
    short code;
    char mods;
public:
    LiKeyCode(short code) : code(code), mods(0) {}
    LiKeyCode(short code, char mods) : code(code), mods(mods) {}
};

/** oh key code --> (win32 vk, modifier bits) */
const std::unordered_map<OH_NativeXComponent_KeyCode, LiKeyCode> codeMap = {
//    {KEY_FN, {}},
//    {KEY_HOME, {}},
//    {KEY_BACK, {}},
    {KEY_MEDIA_PLAY_PAUSE, 0xb3},
    {KEY_MEDIA_STOP, 0xb2},
    {KEY_MEDIA_NEXT, 0xb0},
    {KEY_MEDIA_PREVIOUS, 0xb1},
//    {KEY_MEDIA_REWIND, {}},
//    {KEY_MEDIA_FAST_FORWARD, {}},
    {KEY_VOLUME_UP, 0xaf},
    {KEY_VOLUME_DOWN, 0xae},
//    {KEY_POWER, 0x5f},  // --> computer sleep
//    {KEY_CAMERA, {}},
    {KEY_VOLUME_MUTE, 0xad},
//    {KEY_MUTE, {}}, // mic mute
//    {KEY_BRIGHTNESS_UP, {}},
//    {KEY_BRIGHTNESS_DOWN, {}},
    {KEY_0, 0x30},
    {KEY_1, 0x31},
    {KEY_2, 0x32},
    {KEY_3, 0x33},
    {KEY_4, 0x34},
    {KEY_5, 0x35},
    {KEY_6, 0x36},
    {KEY_7, 0x37},
    {KEY_8, 0x38},
    {KEY_9, 0x39},
    {KEY_STAR, {0x38, MODIFIER_SHIFT}},
    {KEY_POUND, {0x33, MODIFIER_SHIFT}},
//    {KEY_DPAD_UP, {}},
//    {KEY_DPAD_DOWN, {}},
//    {KEY_DPAD_LEFT, {}},
//    {KEY_DPAD_RIGHT, {}},
//    {KEY_DPAD_CENTER, {}},
    {KEY_A, 0x41},
    {KEY_B, 0x42},
    {KEY_C, 0x43},
    {KEY_D, 0x44},
    {KEY_E, 0x45},
    {KEY_F, 0x46},
    {KEY_G, 0x47},
    {KEY_H, 0x48},
    {KEY_I, 0x49},
    {KEY_J, 0x4a},
    {KEY_K, 0x4b},
    {KEY_L, 0x4c},
    {KEY_M, 0x4d},
    {KEY_N, 0x4e},
    {KEY_O, 0x4f},
    {KEY_P, 0x50},
    {KEY_Q, 0x51},
    {KEY_R, 0x52},
    {KEY_S, 0x53},
    {KEY_T, 0x54},
    {KEY_U, 0x55},
    {KEY_V, 0x56},
    {KEY_W, 0x57},
    {KEY_X, 0x58},
    {KEY_Y, 0x59},
    {KEY_Z, 0x5a},
    {KEY_COMMA, 0xbc},
    {KEY_PERIOD, 0xbe},
    {KEY_ALT_LEFT, 0xa4},
    {KEY_ALT_RIGHT, 0xa5},
    {KEY_SHIFT_LEFT, 0xa0},
    {KEY_SHIFT_RIGHT, 0xa1},
    {KEY_TAB, 0x09},
    {KEY_SPACE, 0x20},
    {KEY_SYM, 0x12},   // symbol modifier --> alt/opt
//    {KEY_EXPLORER, {}},
    {KEY_ENVELOPE, 0xb4},  // --> launch mail
    {KEY_ENTER, 0x0d},
    {KEY_DEL, 0x08},   // --> backspace
    {KEY_GRAVE, 0xc0},
    {KEY_MINUS, 0xbd},
    {KEY_EQUALS, 0xbb},
    {KEY_LEFT_BRACKET, 0xdb},
    {KEY_RIGHT_BRACKET, 0xdd},
    {KEY_BACKSLASH, 0xdc},
    {KEY_SEMICOLON, 0xba},
    {KEY_APOSTROPHE, 0xde},
    {KEY_SLASH, 0xbf},
    {KEY_AT, {0x32, MODIFIER_SHIFT}},
    {KEY_PLUS, {0xbb, MODIFIER_SHIFT}},
    {KEY_MENU, 0x5d},
    {KEY_PAGE_UP, 0x21},
    {KEY_PAGE_DOWN, 0x22},
    {KEY_ESCAPE, 0x1b},
    {KEY_FORWARD_DEL, 0x2e},
    {KEY_CTRL_LEFT, 0xa2},
    {KEY_CTRL_RIGHT, 0xa3},
    {KEY_CAPS_LOCK, 0x14},
    {KEY_SCROLL_LOCK, 0x91},
    {KEY_META_LEFT, 0x5b},
    {KEY_META_RIGHT, 0x5c},
    {KEY_FUNCTION, 0x5d},   // function --> applications 
    {KEY_SYSRQ, 0x2c},  // system request / print screen --> print screen
    {KEY_BREAK, 0x13},  // break --> pause
    {KEY_MOVE_HOME, 0x24},
    {KEY_MOVE_END, 0x23},
    {KEY_INSERT, 0x2d},
//    {KEY_FORWARD, 0x},
    {KEY_MEDIA_PLAY, 0xfa},
//    {KEY_MEDIA_PAUSE, },
//    {KEY_MEDIA_CLOSE, }
//    {KEY_MEDIA_EJECT, }
//    {KEY_MEDIA_RECORD, }
    {KEY_F1, 0x70},
    {KEY_F2, 0x71},
    {KEY_F3, 0x72},
    {KEY_F4, 0x73},
    {KEY_F5, 0x74},
    {KEY_F6, 0x75},
    {KEY_F7, 0x76},
    {KEY_F8, 0x77},
    {KEY_F9, 0x78},
    {KEY_F10, 0x79},
    {KEY_F11, 0x7a},
    {KEY_F12, 0x7b},
    {KEY_NUM_LOCK, 0x90},
    {KEY_NUMPAD_0, 0x60},
    {KEY_NUMPAD_1, 0x61},
    {KEY_NUMPAD_2, 0x62},
    {KEY_NUMPAD_3, 0x63},
    {KEY_NUMPAD_4, 0x64},
    {KEY_NUMPAD_5, 0x65},
    {KEY_NUMPAD_6, 0x66},
    {KEY_NUMPAD_7, 0x67},
    {KEY_NUMPAD_8, 0x68},
    {KEY_NUMPAD_9, 0x69},
    {KEY_NUMPAD_DIVIDE, 0x6f},
    {KEY_NUMPAD_MULTIPLY, 0x6a},
    {KEY_NUMPAD_SUBTRACT, 0x6d},
    {KEY_NUMPAD_ADD, 0x6b},
    {KEY_NUMPAD_DOT, 0xbe},
    {KEY_NUMPAD_COMMA, 0xbc},
    {KEY_NUMPAD_ENTER, 0x0d},
    {KEY_NUMPAD_EQUALS, 0xbb},
    {KEY_NUMPAD_LEFT_PAREN, {0x39, MODIFIER_SHIFT}},
    {KEY_NUMPAD_RIGHT_PAREN, {0x30, MODIFIER_SHIFT}},
//    {KEY_VIRTUAL_MULTITASK, },
    {KEY_SLEEP, 0x5f},
    {KEY_ZENKAKU_HANKAKU, 0x19},    // ime kanji mode
//    {KEY_102ND, }
//    {KEY_RO, }
//    {KEY_KATAKANA, 0x},
//    {KEY_HIRAGANA, 0x}
    {KEY_HENKAN, 0x1c},
    {KEY_KATAKANA_HIRAGANA, 0x15},
    {KEY_MUHENKAN, 0x1d},
    {KEY_LINEFEED, 0x0d},
//    {KEY_MACRO, },
//    {KEY_NUMPAD_PLUSMINUS, 0x}
//    {KEY_SCALE, }
    {KEY_HANGUEL, 0x15},
    {KEY_HANJA, 0x19},
//    {KEY_YEN,}
//    {KEY_STOP, },
//    {KEY_AGAIN,}
//    {KEY_PROPS,}
//    {KEY_UNDO,}
//    {KEY_COPY,}
//    {KEY_OPEN, },
//    {KEY_PASTE,}
//    {KEY_FIND,}
//    {KEY_CUT,}
    {KEY_HELP, 0x2f},
//    {KEY_CALC, }
//    {KEY_FILE, }
//    {KEY_BOOKMARKS, }
    {KEY_NEXT, 0xb0},
    {KEY_PLAYPAUSE, 0xb3},
    {KEY_PREVIOUS, 0xb1},
    {KEY_STOPCD, 0xb2},
//    {KEY_CONFIG,}
    {KEY_REFRESH, 0xa8},
//    {KEY_EXIT, 0x}
//    {KEY_EDIT, 0x}
//    {KEY_SCROLLUP,}
//    {KEY_SCROLLDOWN,}
//    {KEY_NEW,}
//    {KEY_REDO,}
//    {KEY_CLOSE, }
    {KEY_PLAY, 0xfa},
//    {KEY_BASSBOOST, }
    {KEY_PRINT, 0x2a},
//    {KEY_CHAT, }
//    {KEY_FINANCE, }
//    {KEY_CANCEL, }
//    {KEY_KBDILLUM_TOGGLE, }
//    {KEY_KBDILLUM_DOWN,}
//    {KEY_KBDILLUM_UP,}
//    {KEY_SEND, }
//    {KEY_REPLY, }
//    {KEY_FORWARDMAIL, }
//    {KEY_SAVE, }
//    {KEY_DOCUMENTS, }
    {KEY_VIDEO_NEXT, 0xb0},
    {KEY_VIDEO_PREV, 0xb1},
//    {KEY_BRIGHTNESS_CYCLE, }
//    {KEY_BRIGHTNESS_ZERO, }
//    {KEY_DISPLAY_OFF, }
//    {KEY_BTN_MISC,}   // rumoured joystick key
//    {KEY_GOTO, }
//    {KEY_INFO,}
//    {KEY_PROGRAM,}
//    {KEY_PVR,}
//    {KEY_SUBTITLE, }
//    {KEY_FULL_SCREEN,}
//    {KEY_KEYBOARD,}
//    {KEY_ASPECT_RATIO,}
//    {KEY_PC, }
//    {KEY_TV,}
//    {KEY_TV2,}
//    {KEY_VCR,}
//    {KEY_VCR2,}
    // ...
    // just why are you putting all these into key code enum????
    //  v-- like wtf is this??? 挡风玻璃除雾器开关???
//    {KEY_FRONT, }
    // dude hear me out, u just can't enumerate all buttons humankind will ever need
    // ...
    {KEY_F13, 0x7c},
    {KEY_F14, 0x7d},
    {KEY_F15, 0x7e},
    {KEY_F16, 0x7f},
    {KEY_F17, 0x80},
    {KEY_F18, 0x81},
    {KEY_F19, 0x82},
    {KEY_F20, 0x83},
    {KEY_F21, 0x84},
    {KEY_F22, 0x85},
    {KEY_F23, 0x86},
    {KEY_F24, 0x87},
    // ...
    {KEY_BTN_0, 0x60},
    {KEY_BTN_1, 0x61},
    {KEY_BTN_2, 0x62},
    {KEY_BTN_3, 0x63},
    {KEY_BTN_4, 0x64},
    {KEY_BTN_5, 0x65},
    {KEY_BTN_6, 0x66},
    {KEY_BTN_7, 0x67},
    {KEY_BTN_8, 0x68},
    {KEY_BTN_9, 0x69},
};
}

bool KeyboardController::handle(OH_NativeXComponent *const comp, void *const win, KeyEvent &event) {
    KeyAction keyAction;
    XCOMP_RETURN_IF_NOT_OK(true, GetKeyEventAction(&event, &keyAction));
    KeyCode keyCode;
    XCOMP_RETURN_IF_NOT_OK(true, GetKeyEventCode(&event, &keyCode));
    if constexpr (DEBUG) {
        OH_LOG_DEBUG(LOG_APP, "Handling action %{public}d code %{public}d", keyAction, keyCode);
    }
    if (!actionMap.contains(keyAction)) {
        OH_LOG_INFO(LOG_APP, "Unmapped key action %{public}d, ignored", keyAction);
        return false;
    }
    if (!codeMap.contains(keyCode)) {
        OH_LOG_INFO(LOG_APP, "Unmapped key code %{public}d, ignored", keyCode);
        return false;
    }
    auto liAction = actionMap.at(keyAction);
    auto liCode = codeMap.at(keyCode);
    LI_CALL_OR_ELSE(SendKeyboardEvent(liCode.code, liAction, liCode.mods),);
    return true;
}
